package com.quyeying.utils.httputils;

import com.quyeying.utils.wx.WxPayConstans;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.Map;

/**
 * @ClassName HttpUtil
 * @Description TODO
 * @Author skx
 * @Date 2021/9/13
 */
@Component
public class HttpUtil {

    private static CloseableHttpClient httpClient = null;
    private static CertificatesManager certificatesManager = null;
    private static Verifier verifier = null;

    /**
     * 通过http协议发送post
     * @param url
     * @param param
     */
    public static String sendPostHttp(String url, Map<String, Object> param){
        RestTemplate restTemplate = new RestTemplate();
        //编码为utf-8
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        HttpHeaders headers = new HttpHeaders();
        //定义请求参数类型，这里用json所以是MediaType.APPLICATION_JSON
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(param, headers);
        ResponseEntity<String> entity = restTemplate.postForEntity(url, request, String.class);
        //获取3方接口返回的数据通过entity.getBody();它返回的是一个字符串；
        return entity.getBody();
    }
    /**
     * 通过http协议发送get
     * @param url
     * @param param
     */
    public static String sendGetHttp(String url, Map<String, Object> param){
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        //处理参数
        StringBuilder builder = new StringBuilder();
        if (param != null) {
            for (String key : param.keySet()) {
                builder.append(key + "=" + param.get(key) + "&");
            }
        }
        ResponseEntity<String> res = restTemplate.getForEntity(url+"?"+builder, String.class);
        return res.getBody();
    }


    /**
     * 使用https协议发送post
     * @param url 请求地址
     * @param param 参数
     */
    public static String sendPostHttps(String url, Map<String, Object> param) {
        RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());
        //编码为utf-8
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        HttpHeaders headers = new HttpHeaders();
        //定义请求参数类型，这里用json所以是MediaType.APPLICATION_JSON
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(param, headers);
        ResponseEntity<String> entity = restTemplate.postForEntity(url, request, String.class);
        //获取3方接口返回的数据通过entity.getBody();它返回的是一个字符串；
        return entity.getBody();
    }

    /**
     * 使用https协议发送get
     * @param url 请求地址
     * @param param 参数
     */
    public static String sendGetHttps(String url, Map<String, Object> param) {
        RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());
        //编码为utf-8
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        //处理参数
        StringBuilder builder = new StringBuilder();
        if (param != null) {
            for (String key : param.keySet()) {
                builder.append(key + "=" + param.get(key) + "&");
            }
        }
        ResponseEntity<String> res = restTemplate.getForEntity(url+"?"+builder, String.class);
        return res.getBody();
    }

    /**
     * 发送xml格式数据
     * @param url
     * @param requestXml
     * @return
     */
    public static String doPost(String url, String requestXml) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        //创建httpClient连接对象
        httpClient = HttpClients.createDefault();
        //创建post请求连接对象
        HttpPost httpPost = new HttpPost(url);
        //创建连接请求对象,并设置连接参数
        RequestConfig requestConfig = RequestConfig.custom()
                //连接服务区主机超时时间
                .setConnectTimeout(15000)
                //连接请求超时时间
                .setConnectionRequestTimeout(60000)
                //设置读取响应数据超时时间
                .setSocketTimeout(60000).build();
        //为httppost请求设置参数
        httpPost.setConfig(requestConfig);
        //将上传参数放到entity属性中
        httpPost.setEntity(new StringEntity(requestXml, "UTF-8"));
        //添加头信息
        httpPost.addHeader("Content-type", "text/xml");
        String result = "";
        try {
            //发送请求
            httpResponse = httpClient.execute(httpPost);
            //从相应对象中获取返回内容
            org.apache.http.HttpEntity entity = httpResponse.getEntity();
            result = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }

    /**
     * <p>
     * 携带证书post请求
     * </p>
     *
     * @param mchId
     * @param url
     * @param data
     * @param certStream
     * @return java.lang.String
     * @author Winder
     * @date 2021/1/25 下午2:51
     */
    public static String doPost(String mchId, String url, String data, InputStream certStream) throws Exception {
        /**
         * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
         */
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        //初始化密钥库
        keyStore.load(certStream, mchId.toCharArray());//这里写密码..默认是你的MCHID

        // Trust own CA and all self-signed certs：信任自己的 CA 和所有自签名证书
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, mchId.toCharArray())//这里也是写密码的
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        try {
            HttpPost httpost = new HttpPost(url);
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                org.apache.http.HttpEntity entity = response.getEntity();

                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

    /**
     * 获取IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 微信通讯client
     * @return CloseableHttpClient
     */
    public static CloseableHttpClient getClient() {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(WxPayConstans.PRIATE_KEY);
        // 获取证书管理器实例
        certificatesManager = CertificatesManager.getInstance();
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(WxPayConstans.MCH_ID, WxPayConstans.MCH_SERIAL_NO, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(getVerifier()))
                .build();
        return httpClient;
    }

    /**
     * 验证器
     * @return verifier
     */
    public static Verifier getVerifier() {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(WxPayConstans.PRIATE_KEY);
        // 获取证书管理器实例
        certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        try {
            certificatesManager.putMerchant(WxPayConstans.MCH_ID, new WechatPay2Credentials(WxPayConstans.MCH_ID,
                            new PrivateKeySigner(WxPayConstans.MCH_SERIAL_NO, merchantPrivateKey)),
                    WxPayConstans.API_V3KEY.getBytes(StandardCharsets.UTF_8));
            // 从证书管理器中获取verifier
            verifier = certificatesManager.getVerifier(WxPayConstans.MCH_ID);
        } catch (GeneralSecurityException | NotFoundException | IOException | HttpCodeException e) {
            e.printStackTrace();
        }
        return verifier;
    }
}

